home *** CD-ROM | disk | FTP | other *** search
- /* lex.c
- *
- * This is the lexical engine
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #include <stdarg.h>
- #include "lex.h"
-
- /************************************************************************/
- /* */
- /* Read Structures */
- /* */
- /************************************************************************/
-
- /* ReadRecord
- *
- * Record storing read/write data
- */
-
- struct ReadRecord {
- char file[64];
- long line;
- int push;
- FILE *fptr;
- };
-
-
- /************************************************************************/
- /* */
- /* Globals */
- /* */
- /************************************************************************/
-
- long GInteger;
- double GReal;
- char GToken[256];
-
- static short GPushToken;
- static int GReadPtr;
- static struct ReadRecord GRead[8];
-
- /************************************************************************/
- /* */
- /* Error management */
- /* */
- /************************************************************************/
-
- /* PrintError
- *
- * Print the error
- */
-
- void PrintError(char *arg,...)
- {
- va_list vlist;
-
- va_start(vlist,arg);
- if (GReadPtr >= 0) {
- fprintf(stderr,"[%s@%ld] ",GRead[GReadPtr].file,GRead[GReadPtr].line);
- }
- vfprintf(stderr,arg,vlist);
- fprintf(stderr,"\n");
- va_end(vlist);
- }
-
- /************************************************************************/
- /* */
- /* Token Search */
- /* */
- /************************************************************************/
-
- /* TokenList
- *
- * List of tokens
- */
-
- struct TokenElement {
- int value;
- char *token;
- } TokenList[] = {
- { KTokenDefine, "define" },
- { KTokenBool, "bool" },
- { KTokenString, "string" },
- { KTokenInteger, "integer" },
- { KTokenClass, "class" },
- { KTokenCreate, "create" },
- { KTokenTrue, "true" },
- { KTokenFalse, "false" },
- { KTokenView, "view" },
- { KTokenRead, "read" },
- { KTokenDimension,"dimension" },
- { -1, NULL }
- };
-
-
- /* TokenSearch
- *
- * It ain't the quickest, but it works
- */
-
- static int TokenSearch(char *str)
- {
- int i;
-
- for (i = 0; TokenList[i].token != NULL; i++) {
- if (!strcmp(TokenList[i].token,str)) return TokenList[i].value;
- }
- return KLexToken;
- }
-
-
- /************************************************************************/
- /* */
- /* Lex Initialization */
- /* */
- /************************************************************************/
-
- /* InitLexEngine
- *
- * This handles initialization of the lexical engine
- */
-
- void InitLexEngine(void)
- {
- GReadPtr = -1;
- GPushToken = -1;
- }
-
- /* EndLexEngine
- *
- * End the lexical parser
- */
-
- void EndLexEngine(void)
- {
- while (GReadPtr >= 0) fclose(GRead[GReadPtr--].fptr);
- GPushToken = -1;
- }
-
- /* ReadLexFile
- *
- * Read a file
- */
-
- void ReadLexFile(char *f)
- {
- FILE *fptr;
-
- if (GReadPtr >= 7) PrintError("Can't open '%s': too many open files",f);
- fptr = fopen(f,"r");
- if (fptr == NULL) PrintError("Can't open '%s': unable to find file",f);
-
- GReadPtr++;
- strcpy(GRead[GReadPtr].file,f);
- GRead[GReadPtr].line = 1;
- GRead[GReadPtr].fptr = fptr;
- GRead[GReadPtr].push = -1;
- }
-
- /************************************************************************/
- /* */
- /* Low level char reader */
- /* */
- /************************************************************************/
-
- /* ReadChar
- *
- * Read a character--this strips out C and C++ style comments
- */
-
- static int ReadChar(void)
- {
- int c;
- int d;
-
- /*
- * Simple screening
- */
-
- if (GReadPtr < 0) return -1;
- if (GRead[GReadPtr].push != -1) {
- c = GRead[GReadPtr].push;
- GRead[GReadPtr].push = -1;
- return c;
- }
-
- /*
- * Pop files that are at EOL
- */
-
- c = fgetc(GRead[GReadPtr].fptr);
- if (c == -1) {
- fclose(GRead[GReadPtr--].fptr);
- return ' ';
- }
-
- /*
- * Update line count
- */
-
- if (c == '\n') GRead[GReadPtr].line++;
-
- /*
- * Strip comments
- */
-
- if (c == '/') {
- d = fgetc(GRead[GReadPtr].fptr);
- if (d == '/') {
- /*
- * Scan for C++ style comment
- */
-
- while ((d != -1) && (d != '\n')) {
- d = fgetc(GRead[GReadPtr].fptr);
- }
- GRead[GReadPtr].line++;
- return '\n';
- }
-
- if (d == '*') {
- /*
- * Scan for C style comment
- */
-
- for (;;) {
- c = fgetc(GRead[GReadPtr].fptr);
- if (c == '\n') {
- GRead[GReadPtr].line++;
- }
- if (c == -1) {
- PrintError("End of comment reached in file");
- GRead[GReadPtr].line++;
- return ' ';
- }
- if (c == '*') {
- c = fgetc(GRead[GReadPtr].fptr);
- if (c == '/') return ' ';
- ungetc(c,GRead[GReadPtr].fptr);
- }
- }
- }
-
- /*
- * Not a comment
- */
-
- ungetc(d,GRead[GReadPtr].fptr);
- }
- return c;
- }
-
- /* PushChar
- *
- * Push character back; store on the GPushChar variable because
- * we're using the available slot in the ungetc for pushing comments
- */
-
- static void PushChar(int c)
- {
- if (GReadPtr >= 0) GRead[GReadPtr].push = c;
- }
-
- /************************************************************************/
- /* */
- /* High level token reader */
- /* */
- /************************************************************************/
-
- /* PushBackToken
- *
- * Push token back
- */
-
- void PushBackToken(int c)
- {
- GPushToken = c;
- }
-
- /* GetNextToken
- *
- * Get the next token
- */
-
- int GetNextToken(void)
- {
- int c;
- int d;
-
- /*
- * Get pushed tokens
- */
-
- if (GPushToken != -1) {
- c = GPushToken;
- GPushToken = -1;
- return c;
- }
-
- /*
- * Get the token
- */
-
- do {
- c = ReadChar();
- } while (isspace(c));
-
- /*
- * What type of character do I have?
- */
-
- if (c == '"') {
- /*
- * Read rest of string (don't use ReadChar--get comments too)
- */
-
- d = 0;
- c = fgetc(GRead[GReadPtr].fptr);
- while ((c != '"') && (c != '\n') && (c != -1)) {
- GToken[d++] = c;
- if (d >= 255) break;
- c = fgetc(GRead[GReadPtr].fptr);
- }
-
- /*
- * Return type
- */
-
- GToken[d] = 0;
- return KLexString;
- }
-
- if ((c == '$') || (c == '_') || isalpha(c)) {
- /*
- * Read rest of token
- */
-
- d = 0;
- while ((c == '$') || (c == '_') || isalnum(c)) {
- GToken[d++] = c;
- if (d >= 255) break;
- c = ReadChar();
- }
- PushChar(c);
-
- /*
- * Null terminate token and return
- */
-
- GToken[d] = 0;
- return TokenSearch(GToken);
- }
-
- if ((c == '-') || (c == '.') || isdigit(c)) {
- /*
- * Look forward if '-' or '.' for number component
- */
-
- if (c == '-') {
- d = ReadChar(); /* Quick readahead */
- PushChar(d);
- if ((d != '.') && !isdigit(d)) {
- GToken[0] = '-';
- GToken[1] = 0;
- return '-';
- }
- } else if (c == '.') {
- d = ReadChar();
- PushChar(d);
- if (!isdigit(d)) {
- GToken[0] = '.';
- GToken[1] = 0;
- return '.';
- }
- }
-
- /*
- * Read the rest of the number
- */
-
- d = 0;
- do {
- GToken[d++] = c;
- if (d >= 255) break;
- c = ReadChar();
- } while ((c == '.') || isdigit(c));
- PushChar(c);
-
- /*
- * Conversion
- */
-
- GToken[d] = 0;
- for (c = 0; GToken[c]; c++) {
- if (GToken[c] == '.') break;
- }
- GInteger = atol(GToken);
- GReal = atof(GToken);
- if (GToken[c]) return KLexReal;
- else return KLexInteger;
- }
-
- /*
- * If we get here, we have a simple token.
- */
-
- GToken[0] = c;
- GToken[1] = 0;
- return c;
- }
-
-